﻿
// ChemGraphicsView.cpp : implementation of the CChemGraphicsView class
//

#include "stdafx.h"
// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "ChemGraphics.h"
#endif

#include "ChemGraphicsDoc.h"
#include "ChemGraphicsView.h"

#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib, "Gdiplus.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CChemGraphicsView

IMPLEMENT_DYNCREATE(CChemGraphicsView, CScrollView)

BEGIN_MESSAGE_MAP(CChemGraphicsView, CScrollView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CChemGraphicsView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_ERASEBKGND()
	ON_WM_SETCURSOR()
//	ON_WM_SIZE()
ON_UPDATE_COMMAND_UI(ID_INDICATOR_POS, &CChemGraphicsView::OnUpdateIndicatorPos)
ON_COMMAND(ID_TOOLS_COLORTABLE, &CChemGraphicsView::OnToolsColortable)
ON_WM_KEYDOWN()
ON_WM_CHAR()
ON_WM_LBUTTONUP()
ON_COMMAND(ID_TOOLS_FILLCOLOR, &CChemGraphicsView::OnToolsFillcolor)
END_MESSAGE_MAP()

// CChemGraphicsView construction/destruction

CChemGraphicsView::CChemGraphicsView()
{
	// TODO: add construction code here

}

CChemGraphicsView::~CChemGraphicsView()
{
}

BOOL CChemGraphicsView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

// CChemGraphicsView drawing

void CChemGraphicsView::OnDraw(CDC* pDC)
{
	CChemGraphicsDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	// TODO: add draw code for native data here
	CRect cRect;
	GetClientRect(&cRect);
	
	m_dcMem.FillSolidRect(cRect, RGB(255,255,255)); //Do mau ne khung ve
	BaseShape *pShape = NULL;
	int count = pDoc->m_arrShape.GetSize();
	for (int i = 0; i < count; i++)
	{
//		pDoc->m_arrShape[i]->Draw(&m_dcMem);
		pShape = pDoc->m_arrShape.GetAt(i);
		switch (pShape->m_nShapeType)
		{
		case TEXT_T:
			pShape->Draw (&m_dcMem);
			break;
		case CIRCLE_T:
			pShape->Draw (&m_dcMem);
			break;
		case RECTANEGLE_T:
			pShape->Draw (&m_dcMem);
			break;
		case LINE_T:
			pShape->Draw (&m_dcMem);
			break;
		case SQUARE_T:
		case ECLIPSE_T:
			pShape->Draw (&m_dcMem);
			break;
		case ARROW_T:
		case TRIBOND_T:
		case DOUBLEBOLDBOND_T:
		case DOUBLEBOND_T:
		case ONEBOND_T:
		case BENZENBOND_T:
		case CYCLOHEXANEBOND_T:
		case CIRCLEBENZENE_T:
		case CYCLOPENTANE_T:
		case HASHEDWEDGE_T:
		case WEDGEBOND_T:
		case HASHBOND_T:
		case WHITEHASHBOND_T:
		case UNDEFINEBOND_T:
		case BOLDBOND_T:
		case DOUBLEARROW_T:
			pShape->Draw (&m_dcMem);
			break;
		case PLUSCIRCLE_T:
		case PLUSPOINT_T:
		case PLUS_T:
		case SUBCIRCLE_T:
		case SUBPOINT_T:
		case SUB_T:
		case ONEPOINT_T:
		case DOUBLEPOINT_T:
			pShape->Draw (&m_dcMem);
			break;
		case OBITALBOLD_T:
		case OBITALCIRCLE_T:
		case OBITALPIE_T:
		case OBITALESCLIPSE_T:
		case OBITALESCLIPSEBOLD_T:
		case OBITALDOUBLEPIE_T:
		case OBITALDOUBLEPIEBOLD_T:
		case OBITALSMFLOWER_T:
		case OBITALFLOWERBOLD_T:
			pShape->Draw (&m_dcMem);
			break;
		default:
			break;
		}
	}
	pDC->BitBlt(0,0,cRect.Width(), cRect.Height(), &m_dcMem, 0, 0, SRCCOPY);
	// draw tracker on outside
	pDoc->m_tracker.Draw(pDC);
	if (!pDoc)
		return;
}


// CChemGraphicsView printing


void CChemGraphicsView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CChemGraphicsView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CChemGraphicsView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing

}

void CChemGraphicsView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CChemGraphicsView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CChemGraphicsView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CChemGraphicsView diagnostics

#ifdef _DEBUG
void CChemGraphicsView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CChemGraphicsView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CChemGraphicsDoc* CChemGraphicsView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CChemGraphicsDoc)));
	return (CChemGraphicsDoc*)m_pDocument;
}
#endif //_DEBUG


// CChemGraphicsView message handlers


int CChemGraphicsView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CScrollView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO:  Add your specialized creation code here
	CClientDC dc(this);
	int x = ::GetSystemMetrics(SM_CXSCREEN);
	int y = ::GetSystemMetrics(SM_CYSCREEN);
	m_dcMem.CreateCompatibleDC(&dc);
	m_bmpMem.CreateCompatibleBitmap(&dc, x, y);
	m_dcMem.SelectObject(&m_bmpMem);

	return 0;
}


void CChemGraphicsView::OnLButtonDown(UINT nFlags, CPoint point)
{
	
	// TODO: Add your message handler code here and/or call default
	CChemGraphicsDoc* pDoc = GetDocument();
	BaseShape* pShape = NULL;
	m_pTBegin = point;

	if(pDoc->m_nShapeType == TRACKER_BITMAP)
    {
        SetCapture();                           // Chặn bắt chuột cho cửa sổ View
        m_rDrag.SetRect(point,point);           // Lưu vị trí bắt đầu Drag
        CView::OnLButtonDown(nFlags,point);     // Gọi lớp cơ sở
        return;                                 // Trở về ngay
    }

	switch (pDoc->m_nShapeType)
	{
	case TEXT_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CText ( point, point, pDoc->m_nShapeType, pDoc->m_szText);
		pDoc->m_arrShape.Add(pShape);
		break;
		//Shape type
	case CIRCLE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CCircle (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case RECTANEGLE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CRectangle (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case LINE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CLine (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case CURVER_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		break;
	case SQUARE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CSquare (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case ECLIPSE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CEclipse (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case ARROW_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CArrow (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
		//Bond type
	case TRIBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CTriBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case DOUBLEBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CDoubleBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case ONEBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new COneBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;	
	case BENZENBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CBenzenBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case CYCLOHEXANEBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CCycloHexaneBone (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case CIRCLEBENZENE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CCircleBenzene (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case CYCLOPENTANE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CCycloPentane (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case HASHEDWEDGE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new CHasheWedge (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case WEDGEBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new CWedgeBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case HASHBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new CHashBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case WHITEHASHBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new CWhiteHashBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case UNDEFINEBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		pShape = new CUndefineBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case BOLDBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CBoldBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	case DOUBLEBOLDBOND_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CDoubleBoldBond (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
		break;
	case DOUBLEARROW_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CDoubleArrow (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		break;
	//Symbol
	case PLUSPOINT_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CPlusPoint ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case PLUSCIRCLE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CPlusCircle ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case PLUS_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CPlus ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case SUBCIRCLE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CSubCircle ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case SUBPOINT_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CSubPoint ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case SUB_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CSub ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	case ONEPOINT_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new COnePoint ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case DOUBLEPOINT_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CDoublePoint ( point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
		//Obital
	case OBITALCIRCLE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalCircle (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case OBITALBOLD_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalBold (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;

	case OBITALPIE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalPie (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case OBITALPIEBOLD_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalPieBold (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;
	case OBITALESCLIPSE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalEsclipe (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	case OBITALESCLIPSEBOLD_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalEsclipeBold (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		Invalidate();
		break;	
	case OBITALDOUBLEPIE_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalFlower (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	case OBITALDOUBLEPIEBOLD_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalFlowerBold (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	case OBITALSMFLOWER_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalSmallFlower (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	case OBITALSMFLOWERBOLD_T:
		pDoc->DeleteTracker();
		m_bFlagShape = TRUE;
		m_bFlagMove = FALSE;
		pShape = new CObitalBSmallFlower (point, point, pDoc->m_clrBack, pDoc->m_cPenColor, pDoc->m_nShapeType);
		pDoc->m_arrShape.Add(pShape);
		Invalidate();
		break;	
	//SELECT OBJECT
	case SELECT_T:
		m_bFlagShape = FALSE;
		INT m_nShapeCurrent;
		
		m_nShapeCurrent	= pDoc->isPointShape(point);
		if(m_nShapeCurrent > -1)
		{
			pDoc->m_tracker.m_rect.TopLeft() = pDoc->m_arrShape[m_nShapeCurrent]->m_pMax;
			pDoc->m_tracker.m_rect.BottomRight() = pDoc->m_arrShape[m_nShapeCurrent]->m_pMin;
			CRect rectSave;
			pDoc->m_tracker.GetTrueRect(rectSave);
			if (pDoc->m_tracker.HitTest(point) < 0)
			{
				CRectTracker tracker;
				if (tracker.TrackRubberBand(this, point, pDoc->m_bAllowInvert))
				{
					MessageBeep(0);
					CRect rectT;
					tracker.m_rect.NormalizeRect();
					if (rectT.IntersectRect(tracker.m_rect, pDoc->m_tracker.m_rect))
					{
						if (pDoc->m_tracker.m_nStyle & CRectTracker::resizeInside)
						{
							pDoc->m_tracker.m_nStyle &= ~CRectTracker::resizeInside;
							pDoc->m_tracker.m_nStyle |= CRectTracker::resizeOutside;
						}
						else
						{
							pDoc->m_tracker.m_nStyle &= ~CRectTracker::resizeOutside;
							pDoc->m_tracker.m_nStyle |= CRectTracker::resizeInside;
						}
						pDoc->SetModifiedFlag();
						pDoc->UpdateAllViews(NULL, (LPARAM)(LPCRECT)rectSave);
						pDoc->UpdateAllViews(NULL);
					}
				}
			}
			else if (pDoc->m_tracker.Track(this, point, pDoc->m_bAllowInvert))
			{
				// normal tracking action, when tracker is "hit"
				pDoc->SetModifiedFlag();
				pDoc->UpdateAllViews(NULL, (LPARAM)(LPCRECT)rectSave);
				pDoc->UpdateAllViews(NULL);
			}
			pDoc->m_arrShape[m_nShapeCurrent]->m_pBegin += pDoc->m_tracker.m_rect.TopLeft() - pDoc->m_arrShape[m_nShapeCurrent]->m_pMax;
			pDoc->m_arrShape[m_nShapeCurrent]->m_pEnd	+= pDoc->m_tracker.m_rect.BottomRight() - pDoc->m_arrShape[m_nShapeCurrent]->m_pMin;
			Invalidate();
			if(pDoc->m_arrShape[m_nShapeCurrent]->m_nShapeType == TEXT_T)
			{
				pDoc->m_CurrText = m_nShapeCurrent;
				CreateNewCaret(FALSE);
			}
			else
			{
				CreateNewCaret(TRUE);
				pDoc->m_CurrText = -1;
			}
		}
		else
		{
			pDoc->DeleteTracker();
			Invalidate();
		}
		/*
		m_nShapeCurrent2 = pDoc->isPointShape2(point);
		if(m_nShapeCurrent2 >= -1)
		{
			int m_nNumOfShape = (int)pDoc->m_arrShape.GetSize();
			for(int i = 0; i < m_nNumOfShape; i++ )
				pDoc->m_arrShape[i]->m_bSelected = FALSE;
			if(m_nShapeCurrent2 != -1)
			{
				pDoc->m_arrShape[m_nShapeCurrent2]->m_bSelected = TRUE;
				m_bFlagMove = TRUE;
			}
			Invalidate();
		}

		m_nShapeCurrent3 = pDoc->isPointShape3(point);
		if(m_nShapeCurrent3 > -1)
		{
			pDoc->m_arrShape[m_nShapeCurrent3]->m_bSelected = TRUE;
			Invalidate();
		}
		*/

		break;
	}
	
	int count = pDoc->m_arrShape.GetSize();
	if(count >= 1)
	if(pDoc->m_arrShape[count-1]->m_nShapeType == TEXT_T)
	{
		pDoc->m_CurrText = count - 1;
		CreateNewCaret(FALSE);
	}
	UpdateWindow();
	CScrollView::OnLButtonDown(nFlags, point);
}


void CChemGraphicsView::OnMouseMove(UINT nFlags, CPoint point)
{
	CChemGraphicsDoc* doc = GetDocument();
	m_pTEnd = point;

	if(doc->m_nShapeType == TRACKER_BITMAP)
    {
        if(GetCapture() == this)                    // Nếu cửa sổ View đang có toàn quyền với chuột
        if((nFlags & MK_LBUTTON) == MK_LBUTTON)     // Chắc chắn rằng đang Drag
        if( abs(m_rDrag.left - point.x) > 0 || abs(m_rDrag.top - point.y) > 0 )
        {
            CClientDC   dc(this);                   // Nhận thiết bị ngữ cảnh cửa sổ View
            CBrush      brushWhite(RGB(255,255,255));
            CBrush      brushRed(RGB(255,0,0));
            CRect       rTemp;
            // Xóa hình chữ nhật trước đó với màu trắng
            rTemp.CopyRect(&m_rDrag);
            rTemp.NormalizeRect();                  // rTemp sẽ chứa số liệu phù hợp ( left < right  && top < bottom )
            if(!rTemp.IsRectEmpty())
                //this->Invalidate(false);
                //this->InvalidateRect(rTemp,false);
                dc.FrameRect(&rTemp,&brushWhite);
            brushWhite.DeleteObject();     
            // Vẽ một hình chữ nhật với màu đỏ
            m_rDrag.right = point.x;
            m_rDrag.bottom = point.y;
            rTemp.CopyRect(&m_rDrag);
            rTemp.NormalizeRect();
            if(!rTemp.IsRectEmpty())
                dc.FrameRect(&rTemp,&brushRed);    
            brushRed.DeleteObject();
        }
        //CView::OnMouseMove(nFlags,point);
        return;                                 // Trở về ngay
    }

	// TODO: Add your message handler code here and/or call default
	if (nFlags == MK_LBUTTON && m_bFlagShape == TRUE)
	{
			int count = doc->m_arrShape.GetSize();
			doc->m_arrShape[count-1]->m_pEnd = point;
			doc->SetModifiedFlag(TRUE);
			Invalidate();
	}
	CScrollView::OnMouseMove(nFlags, point);
}



BOOL CChemGraphicsView::OnEraseBkgnd(CDC* pDC)
{
	// TODO: Add your message handler code here and/or call default
	return true;
}



void CChemGraphicsView::OnUpdate(CScrollView* /*pSender*/, LPARAM lHint, CObject* /*pHint*/)
{
	// TODO: Add your specialized code here and/or call the base class
	
	if (lHint == 0)
	{
		CChemGraphicsDoc* pDoc = GetDocument();
		CRect rectTrue;
	
		pDoc->m_tracker.GetTrueRect(&rectTrue);
		InvalidateRect(rectTrue);
	}
	else
	{
		InvalidateRect((CRect*)lHint);
	}

}


BOOL CChemGraphicsView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	
	// TODO: Add your message handler code here and/or call default
	CChemGraphicsDoc* pDoc = GetDocument();
	if (pWnd == this && pDoc->m_tracker.SetCursor(this, nHitTest))
		return TRUE;
		
	return CScrollView::OnSetCursor(pWnd, nHitTest, message);
	
}





void CChemGraphicsView::OnUpdateIndicatorPos(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CString StrPos;
	StrPos.Format (_T("X: %d | Y: %d"), m_pTEnd.x, m_pTEnd.y);
	pCmdUI->Enable(TRUE);
	pCmdUI->SetText(StrPos);
}


void CChemGraphicsView::OnToolsColortable()
{
	// TODO: Add your command handler code here
	CChemGraphicsDoc *pDoc = GetDocument();
	CColorDialog ColorDlg;
	if (ColorDlg.DoModal() == IDOK)
	{
		pDoc->m_cPenColor = ColorDlg.GetColor();
	}
}

void CChemGraphicsView::OnToolsFillcolor()
{
	// TODO: Add your command handler code here
	CChemGraphicsDoc *pDoc = GetDocument ();
	CColorDialog ColorDlg;
	if (ColorDlg.DoModal() == IDOK )
	{
		pDoc->m_clrBack = ColorDlg.GetColor();
	}
}


void CChemGraphicsView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	CSize sizeTotal;
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);
	// TODO: Add your specialized code here and/or call the base class
}

void CChemGraphicsView::RedrawCaret() 
{ 
	CChemGraphicsDoc *ptrDoc;
	ptrDoc=(CChemGraphicsDoc *)GetDocument(); 
	HideCaret();
	SetCaretPos(ptrDoc->GetCaretPosition());
	ShowCaret();
}

void CChemGraphicsView::CreateNewCaret(BOOL bDestroy)
{ 
	CChemGraphicsDoc *ptrDoc;
	if(bDestroy == TRUE)::DestroyCaret();
	ptrDoc=(CChemGraphicsDoc *)GetDocument();
	CreateSolidCaret(0, ptrDoc->GetCaretVerSize());
	SetCaretPos(ptrDoc->GetCaretPosition());
	ShowCaret();
}


void CChemGraphicsView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	CChemGraphicsDoc *ptrDoc;
	SHORT nKeyState;

	ptrDoc=(CChemGraphicsDoc *)GetDocument();
	ASSERT(ptrDoc);
	switch(nChar) 
	{
	case VK_LEFT:
		{
			nKeyState = GetKeyState(VK_CONTROL); 
			if(HIBYTE(nKeyState) != 0) 
			{
				ptrDoc->BackwardCaretToBlank(); 
			}
			else ptrDoc->BackwardCaret(); 
			break;
		}
	case VK_RIGHT: 
		{
			nKeyState=GetKeyState(VK_CONTROL); 
			if(HIBYTE(nKeyState) != 0) 
			{
				ptrDoc->ForwardCaretToBlank();
			} 
			else ptrDoc->ForwardCaret();
			break;
		}
	case VK_DELETE: 
		{
			ptrDoc->DeleteChar(FALSE);
			break; 
		}
	case VK_END: 
		{
			ptrDoc->EndCaret();
			break;
		}
	case VK_HOME:
		{ 
			ptrDoc->HomeCaret();
			break; 
		}
	}
	CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}


void CChemGraphicsView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	CChemGraphicsDoc *ptrDoc;
	ptrDoc=(CChemGraphicsDoc *)GetDocument(); 
	if(nChar != VK_RETURN && nChar != VK_ESCAPE && nChar != VK_TAB)
	{ 
		if(nChar == VK_BACK)ptrDoc->DeleteChar(TRUE);
		else ptrDoc->AddChar(nChar, nRepCnt);
	} 
	CScrollView::OnChar(nChar, nRepCnt, nFlags);
}

/******************Modul Save Bitmap File**********************/
/*	+	Cap nhat ngay: 10/11/2014
	+	Author: Nguyen Minh Tri
	+	Description: save bitmap file with GDI+ library
***************************************************************/
void CChemGraphicsView::ShowErrorWin32()
{
    LPVOID      pMessage;
 
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &pMessage,0,NULL);
    MessageBox((LPCTSTR)pMessage, _T("SaveAs"), MB_OK | MB_ICONINFORMATION );
    LocalFree(pMessage);
}

void CChemGraphicsView::ShowErrorGdiplus(int iStatus)
{
	CHAR            szText[MAX_PATH];
    switch(iStatus)
    {
    case GenericError:                  wsprintf( (LPWSTR)szText,_T("ErrorString: GenericError") ); break;
    case InvalidParameter:              wsprintf( (LPWSTR)szText,_T("ErrorString: InvalidParameter") ); break;
    case OutOfMemory:                   wsprintf( (LPWSTR)szText,_T("ErrorString: OutOfMemory") ); break;
    case ObjectBusy:                    wsprintf( (LPWSTR)szText,_T("ErrorString: ObjectBusy") ); break;
    case InsufficientBuffer:            wsprintf( (LPWSTR)szText,_T("ErrorString: InsufficientBuffer") ); break;
    case NotImplemented:                wsprintf( (LPWSTR)szText,_T("ErrorString: NotImplemented") ); break;
    case WrongState:                    wsprintf( (LPWSTR)szText,_T("ErrorString: WrongState") ); break;
    case Aborted:                       wsprintf( (LPWSTR)szText,_T("ErrorString: Aborted") ); break;
    case FileNotFound:                  wsprintf( (LPWSTR)szText,_T("ErrorString: FileNotFound") ); break;
    case ValueOverflow:                 wsprintf( (LPWSTR)szText,_T("ErrorString: ValueOverflow") ); break;
    case AccessDenied:                  wsprintf( (LPWSTR)szText,_T("ErrorString: AccessDenied") ); break;
    case UnknownImageFormat:            wsprintf( (LPWSTR)szText,_T("ErrorString: UnknownImageFormat") ); break;
    case FontFamilyNotFound:            wsprintf( (LPWSTR)szText,_T("ErrorString: FontFamilyNotFound") ); break;
    case FontStyleNotFound:             wsprintf( (LPWSTR)szText,_T("ErrorString: FontStyleNotFound") ); break;
    case NotTrueTypeFont:               wsprintf( (LPWSTR)szText,_T("ErrorString: NotTrueTypeFont") ); break;
    case UnsupportedGdiplusVersion:     wsprintf( (LPWSTR)szText,_T("ErrorString: UnsupportedGdiplusVersion") ); break;
    case GdiplusNotInitialized:         wsprintf( (LPWSTR)szText,_T("ErrorString: GdiplusNotInitialized") ); break;
    case PropertyNotFound:              wsprintf( (LPWSTR)szText,_T("ErrorString: PropertyNotFound") ); break;
    case PropertyNotSupported:          wsprintf( (LPWSTR)szText,_T("ErrorString: PropertyNotSupported") ); break;
    default:                            wsprintf( (LPWSTR)szText,_T("ErrorString: Unknow") ); break;
    }
    MessageBox((LPWSTR)szText,_T("SaveAs"), 0);
	
}

int CChemGraphicsView::GetEncoderClsid(const WCHAR * wszEncoder, CLSID * pClsid)
{
	UINT				i,cCount,cSize;
		ImageCodecInfo *	pInfo = NULL;

		GetImageEncodersSize(&cCount, &cSize);
		if(cSize == 0)
			return -1;
		pInfo = (ImageCodecInfo*)(malloc(cSize));
		if(pInfo == NULL)
			return -1;
		GetImageEncoders(cCount, cSize, pInfo);
		for( i = 0; i < cCount; ++i)
		{
			if( wcscmp(pInfo[i].MimeType, wszEncoder) == 0 )
			{
				*pClsid = pInfo[i].Clsid;
				free(pInfo);
				return i;
			}
		}
		free(pInfo);
		return -1;
}

void CChemGraphicsView::ExportToPicture()
{
	try
	{
	CFileDialog     dlg(false,_T("bmp"),NULL,OFN_OVERWRITEPROMPT|OFN_EXTENSIONDIFFERENT,_T("Files Bitmap (*.bmp)|*.bmp|Files Gif (*.gif)|*.gif|Files JPEG (*.jpg)|*.jpg|Files Png (*.png)|*.png|Files TIFF (*.tif)|*.tif||" ),this);
        if(IDOK == dlg.DoModal())
        {
            CRect   r;
            int     cx,cy;
            CDC *   pdc;
            CDC     dcMem;
            CBitmap bm;
 
            GetClientRect(&r);
            cx = r.right - r.left;
            cy = r.bottom - r.top;
            pdc = this->GetDC();
            dcMem.CreateCompatibleDC(pdc);
            if(!bm.CreateCompatibleBitmap(pdc,cx,cy))
            {
                dcMem.DeleteDC();
                this->ReleaseDC(pdc);
                MessageBox(_T("CreateCompatibleBitmap falure"),_T("SaveAs"), 0);
                return;
            }
            dcMem.SelectObject(&bm);
            dcMem.BitBlt(0,0,cx,cy,pdc,0,0,SRCCOPY);
            dcMem.DeleteDC();
            this->ReleaseDC(pdc);
 
            GdiplusStartupInput     gdiplusStartupInput;
            ULONG_PTR               gdiplusToken;
            CLSID                   clsid;
            Bitmap *                pBitmap;
            PWCHAR                  pwChar[5] = {L"image/bmp",L"image/gif",L"image/jpeg",L"image/png",L"image/tiff"};
 
            GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
            if(GetEncoderClsid( pwChar[dlg.m_ofn.nFilterIndex-1], &clsid) == -1)
            {
                bm.DeleteObject();
                GdiplusShutdown(gdiplusToken);
                MessageBox(_T("GetEncoderClsid falure"),_T("SaveAs"), 0);
                return;
            }
#ifdef new
#undef new
            pBitmap = new Bitmap(bm,NULL);
#define new DEBUG_NEW
#else
            pBitmap = new Bitmap(bm,NULL);
#endif
            int iStatus = pBitmap->Save(dlg.m_ofn.lpstrFile, &clsid, NULL);
            delete pBitmap;
            bm.DeleteObject();
            GdiplusShutdown(gdiplusToken);
            if(iStatus == Ok)
                MessageBox(_T("Saved SUCCESSED"),_T("SaveAs"), 0);
            else if(iStatus == Win32Error)
                ShowErrorWin32();
            else
                ShowErrorGdiplus(iStatus);
        }
    }
    catch(...)
    {
    }
}

void CChemGraphicsView::ExportToPicture(CRect r)  // Ở đây có tham số CRect
{
    try
    {
        CFileDialog     dlg(false,_T("bmp"),NULL,OFN_OVERWRITEPROMPT|OFN_EXTENSIONDIFFERENT,_T("Files Bitmap (*.bmp)|*.bmp|Files Gif (*.gif)|*.gif|Files JPEG (*.jpg)|*.jpg|Files Png (*.png)|*.png|Files TIFF (*.tif)|*.tif||" ),this);
        if(IDOK == dlg.DoModal())
        {
            //CRect   r;
            int     cx,cy;
            CDC *   pdc;
            CDC     dcMem;
            CBitmap bm;
 
            //GetClientRect(&r);
 
            cx = r.right - r.left;
            cy = r.bottom - r.top;
            pdc = this->GetDC();
            dcMem.CreateCompatibleDC(pdc);
            if(!bm.CreateCompatibleBitmap(pdc,cx,cy))
            {
                dcMem.DeleteDC();
                this->ReleaseDC(pdc);
                MessageBox(_T("CreateCompatibleBitmap falure"),_T("SaveAs"), 0);
                return;
            }
            dcMem.SelectObject(&bm);
            //dcMem.BitBlt(0,0,cx,cy,pdc,0,0,SRCCOPY);
            dcMem.BitBlt(0,0,cx,cy,pdc,r.left,r.top,SRCCOPY);
            dcMem.DeleteDC();
            this->ReleaseDC(pdc);
// ................................................ đoạn bên dưới không cần thay đổi
			GdiplusStartupInput     gdiplusStartupInput;
            ULONG_PTR               gdiplusToken;
            CLSID                   clsid;
            Bitmap *                pBitmap;
            PWCHAR                  pwChar[5] = {L"image/bmp",L"image/gif",L"image/jpeg",L"image/png",L"image/tiff"};
 
            GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
            if(GetEncoderClsid( pwChar[dlg.m_ofn.nFilterIndex-1], &clsid) == -1)
            {
                bm.DeleteObject();
                GdiplusShutdown(gdiplusToken);
                MessageBox(_T("GetEncoderClsid falure"),_T("SaveAs"), 0);
                return;
            }
#ifdef new
#undef new
            pBitmap = new Bitmap(bm,NULL);
#define new DEBUG_NEW
#else
            pBitmap = new Bitmap(bm,NULL);
#endif
            int iStatus = pBitmap->Save(dlg.m_ofn.lpstrFile, &clsid, NULL);
            delete pBitmap;
            bm.DeleteObject();
            GdiplusShutdown(gdiplusToken);
            if(iStatus == Ok)
                MessageBox(_T("Saved SUCCESSED"),_T("SaveAs"), 0);
            else if(iStatus == Win32Error)
                ShowErrorWin32();
            else
                ShowErrorGdiplus(iStatus);
        }
    }
    catch(...)
    {
    }
}

void CChemGraphicsView::OnLButtonUp(UINT nFlags, CPoint point)
{
	CChemGraphicsDoc *pDoc = GetDocument();
	// TODO: Add your message handler code here and/or call default
	if(pDoc->m_nShapeType == TRACKER_BITMAP)
    {
        if(GetCapture() == this)                // Nếu cửa sổ View đang có toàn quyền với chuột
        {
            ReleaseCapture();                   // Giải phóng chuột về lại cho hệ thống
 
            CRect   rTemp;
            rTemp.CopyRect(&m_rDrag);
            rTemp.NormalizeRect();                  // rTemp sẽ chứa số liệu phù hợp ( left < right  && top < bottom )
            this->Invalidate(false);
 
            ExportToPicture(rTemp);  // Xuất ra tập tin hình ảnh theo chữ nhật Drag
            pDoc->m_nShapeType = RECTANEGLE_T;
        }
        CView::OnLButtonUp(nFlags,point);       // Gọi lớp cơ sở
        return;                                 // Trở về ngay
    }
	CScrollView::OnLButtonUp(nFlags, point);
}


